/*
 * server.cpp
 *
 *  Created on: 19/10/2011
 *      Author: diego
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sstream>
#include "Clases/MotorBusqueda.h"

#define PORT_NUMBER 9025

typedef struct header_t{
	int tamano;
}header;

void error(const char *msg) {
	perror(msg);
	exit(1);
}

int main(int argc, char *argv[]) {
	int sock_descriptor, newsocket_descriptor, port_number;
	char killMessage[] = "#_KILL_SERVER_#";
	socklen_t clientlen;
	char buffer[256];
	struct sockaddr_in server_addr, client_addr;
	int n;
	/*
	 if (argc < 2) {
	 fprintf(stderr,"ERROR, tenes que especificar el puerto\n");
	 exit(1);
	 }
	 */
	sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);
	if (sock_descriptor < 0) {
		error("no se pudo abrir el socket");
	}

	int opt = 1;
	setsockopt(sock_descriptor, SOL_SOCKET, SO_REUSEADDR, (char *) &opt,
			sizeof(opt));

	// inicializo a cero todo. el struct
	bzero((char *) &server_addr, sizeof(server_addr));

	// como parametro se le pasa el numero de puerto por el cual
	// va a estar escuchando el servidor
	//port_number = atoi(argv[1]);
	port_number = PORT_NUMBER;

	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = INADDR_ANY;

	// esta funcion hace una cosa rara con el numero del
	// puerto que nunca entendi
	server_addr.sin_port = htons(port_number);

	// le digo al SO que me asocie el socket que abri con el puerto
	int bind_response = bind(sock_descriptor, (struct sockaddr *) &server_addr,
			sizeof(server_addr));
	if (bind_response < 0) {
		error("no se pudo asociar el socket con el puerto");
	}

	//creo el archivo para indicar que el server esta corriendo
	ofstream* fd = new ofstream(".server.run");
	fd->close();
	delete fd;

	//Levanto el Motor de Busqueda
	MotorBusqueda motorBusqueda;

	// me pongo a escuchar en el puerto a travez del socket
	listen(sock_descriptor, 5);
	clientlen = sizeof(client_addr);

	bool salir = false;
	while (!salir) {
		// se bloquea la ejecucion hasta que se conecte un cliente
		// y se acepte la conexion
		newsocket_descriptor = accept(sock_descriptor,
				(struct sockaddr *) &client_addr, &clientlen);

		if (newsocket_descriptor < 0) {
			error("error al aceptar la conexion");
		}

		// inicializo en cero el buffer
		bzero(buffer, 256);
		// leo en el nuevo socket
		n = read(newsocket_descriptor, buffer, 255);
//cout << "server: " << buffer << endl;
		if (n < 0) {
			error("error al leer el socket");
		}

		string s = "";

		if (strncmp(buffer, killMessage, 15) != 0) {
			//cout << "HOLAAa" << endl;
			string query(buffer);
			Lista<reg_rank>* lista = motorBusqueda.buscar(query);

			IteradorLista<reg_rank> it = lista->iterador();
			while (it.tieneSiguiente()){
				reg_rank reg = it.siguiente();

				stringstream ss;
				//cout << reg.documento << endl;
				ss << reg.documento;
				s += ss.str() + " ";
				ss.clear();
			}

			// saco el ultimo espacio que puse
			s = s.substr(0, s.length() -1);

			//cout << "server: " << s << endl;

			header head;
			head.tamano = s.length();

			// primero escribo la cabecera
			n = write(newsocket_descriptor, &head, sizeof(head));

			if (n < 0) {
				error("error al escribir en el socket");
			}

			// escribo los ids
			n = write(newsocket_descriptor, s.c_str(), s.length());

			if (n < 0) {
				error("error al escribir en el socket");
			}
		} else {
			salir = true;
		}
	}

	// cierro los dos socket que abri
	close(newsocket_descriptor);
	close(sock_descriptor);

	// borro el archivo cuando termina el server
	remove(".server.run");

	return 0;
}

